import { setModel, getModel } from '../state/model.js';
import ELBuilder from '../model/builder.js';

export const createHistory = () => {
  const state = {
    stack: [],
    cursor: 0,
    graph: null,
  };

  return {
    init(graph) {
      state.graph = graph;
      state.stack = [];
      state.cursor = 0;
    },
    canRedo() {
      return state.cursor < state.stack.length - 1;
    },
    canUndo() {
      return state.cursor > 0;
    },
    push(nextState, options = { silent: false }) {
      if (state.stack.length > state.cursor + 1) {
        state.stack.splice(state.cursor + 1, state.stack.length - state.cursor);
      }

      if (nextState) {
        state.stack.push(nextState.toJSON());
      } else if (getModel()) {
        state.stack.push(getModel().toJSON());
      }
      state.cursor += 1;

      if (!options.silent && state.graph) {
        state.graph.trigger('model:change');
        state.graph.trigger('toolBar:forceUpdate');
        state.graph.trigger('settingBar:forceUpdate');
      }
    },
    redo() {
      if (this.canRedo()) {
        state.cursor += 1;
        setModel(ELBuilder.build(state.stack[state.cursor]));
        if (state.graph) {
          state.graph.trigger('model:change');
          state.graph.trigger('toolBar:forceUpdate');
          state.graph.trigger('settingBar:forceUpdate');
        }
      }
    },
    undo() {
      if (this.canUndo()) {
        state.cursor -= 1;
        setModel(ELBuilder.build(state.stack[state.cursor]));
        if (state.graph) {
          state.graph.trigger('model:change');
          state.graph.trigger('toolBar:forceUpdate');
          state.graph.trigger('settingBar:forceUpdate');
        }
      }
    },
    cleanHistory() {
      if (getModel()) {
        state.stack = [getModel().toJSON()];
        state.cursor = 0;
        if (state.graph) {
          state.graph.trigger('model:change');
          state.graph.trigger('toolBar:forceUpdate');
          state.graph.trigger('settingBar:forceUpdate');
        }
      }
    },
    length() {
      return state.stack.length ? state.stack.length - 1 : 0;
    },
    snapshot() {
      return {
        stack: [...state.stack],
        cursor: state.cursor,
      };
    },
  };
};

export const history = createHistory();

